home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Ian & Stuart's Australian Mac 1993 September
/
September 93.iso
/
Archives
/
Sound
/
MIDI
/
MIDI Utilities
/
CMU Midi Toolkit
/
Source
/
adagio.c
next >
Wrap
C/C++ Source or Header
|
1988-01-29
|
16KB
|
590 lines
/* adagio.c -- user interface to adagio play and record */
/*****************************************************************************
* Change Log
* Date | Change
*-----------+-----------------------------------------------------------------
* 12-Mar-86 | Created
* 28-May-86 | Added calls to cmdline.c for command line parsing
* 2-Oct-86 | JMaloney: Converted to Macintosh
* | Removed -xt, -at, and -metronome switches
* 7-Jan-87 | JMaloney: Converted to Lightspeed C
* | Moved command loop here from phase2
* 29-Jan-87 | JMaloney: Enabled reading of new score files
* 12-Jan-88 | Dannenberg: new modal command loops, same funtionality
* 29-Jan-88 | Dannenberg: made some user commands case insensitive
*****************************************************************************/
#include "switches.h"
#ifdef LIGHTSPEED
#include <Proto.h>
#include <StdIO.h>
#include <MemoryMgr.h>
#endif
#ifdef MPW
#include <StdIO.h>
#include <Types.h>
#include <Memory.h>
#endif
#include "CType.h"
#include "cext.h"
#include "adagio.h"
#include "cmdline.h"
#include "stream.h"
#include "filestream.h"
#include "mpu.h"
#include "noteoff.h"
#include "phase1.h"
#include "phase2.h"
#include "record.h"
#include "userio.h"
/****************************************************************************
*
* command line switches and options
*
****************************************************************************/
#define nswitches 12
private char *switches[nswitches] =
{"-debug", "-d", "-help", "-h", "-miditrace", "-m", "-trace", "-t",
"-simulated", "-s", "-print", "-block"};
#define noptions 3
private char *options[noptions] = {"-c", "-control", "-tune"};
/****************************************************************************
*
* variables shared with other modules
*
****************************************************************************/
extern boolean musictrace; /* read by report_modes */
extern boolean miditrace; /* read by report_modes */
/****************************************************************************
*
* macros and constants
*
****************************************************************************/
#define LINE_SIZE 100
/****************************************************************************
*
* routines private to this module
*
****************************************************************************/
void cmdline_help(void);
void cmd_help(void);
void cmd_loop(event_type);
void default_response(char);
event_type new_score(char *);
void play_mode();
void record_mode();
void transcribe_mode();
void play_pause_loop(event_type, ulong, StreamPtr);
void report_activity(event_type, ulong);
void report_modes(void);
void report_stop(event_type, ulong, int);
void _main(int argc, char *argv[]);
static ulong startTime = 0;
/****************************************************************************
* cmdline_help
* Effect:
* list command line switches and options
****************************************************************************/
private void cmdline_help()
{
gprintf(TRANS, "adagio [options]\n");
gprintf(TRANS, " options are:\n");
/* gprintf(TRANS, " -block disable MIDI thru\n");*/
gprintf(TRANS, " -control (-c) [on|off] en/disable continuous controller recording\n");
gprintf(TRANS, " -debug (-d) enable verbose debug mode\n");
gprintf(TRANS, " -help (-h) print this message\n");
gprintf(TRANS, " -miditrace (-m) turn on MIDI command trace\n");
gprintf(TRANS, " -print print note data\n");
gprintf(TRANS, " -tune file use tuning from file\n");
gprintf(TRANS, " -simulated (-s) run with simulated midi device\n");
gprintf(TRANS, " -trace (-t) turn on music operation trace\n\n");
gprintf(TRANS, "\n");
}
/****************************************************************************
* cmd_help
* Effect:
* help for command interpreter
****************************************************************************/
private void cmd_help()
{
gprintf(TRANS, "\n");
gprintf(TRANS, " <Return> play\n");
gprintf(TRANS, " q quit this mode\n");
gprintf(TRANS, " b begin at a particular time\n");
gprintf(TRANS, " m toggle MIDI byte trace mode\n");
gprintf(TRANS, " t toggle music operation trace mode\n");
gprintf(TRANS, " s report operation mode\n");
gprintf(TRANS, " u read a tuning file\n");
gprintf(TRANS, " ?,<other> display this message\n");
gprintf(TRANS, "\n");
}
/****************************************************************************
* cmd_loop
* Inputs:
* event_type score: score to play
* Effect:
* a simple command interpreter for single key commands
****************************************************************************/
private void cmd_loop(score)
event_type score;
{
char userinput[100];
char response;
boolean done = false;
while (!done) {
*userinput = 0;
while (*userinput == 0 || !isalpha(*userinput)) {
gprintf(TRANS, "Type a for Adagio, t for transcribe, r for record: ");
gets(userinput);
}
response = tolower(*userinput);
switch (response) {
case 'a':
play_mode();
break;
case 'r':
record_mode();
break;
case 't':
transcribe_mode();
break;
}
}
}
/* default_response -- handle things common to play, transcribe, record */
/**/
void default_response(response)
char response;
{
response = tolower(response);
switch (response) {
case 'b':
{
char userInput[LINE_SIZE];
gprintf(TRANS, "Type starting time (in hundredths of seconds)\n");
gets(userInput);
if (sscanf((byte *) userInput, "%ld", &startTime) != 1) {
gprintf(TRANS, "Bad start time!\n");
startTime = 0;
}
}
break;
case 'm':
tracemidi(!miditrace);
report_modes();
break;
case 's':
report_modes();
break;
case 't':
trace(!musictrace);
report_modes();
break;
case 'u':
read_tuning("");
break;
case '?':
default:
cmd_help();
break;
}
}
/****************************************************************************
* new_score
* Inputs:
* char * defaultFile: the file name from command line or NULL
* Returns:
* event_type: the new score or NULL
* Effect:
* if defaultFile is not NULL, it is read
* otherwise new_score prompts for file name and attempts to read that file
* if the user doesn't supply a file name when prompted or if the
* open operation fails, the NULL score is returned
* Implementation:
* any existing score is freed before reading a new score
****************************************************************************/
event_type new_score(defaultFile)
char *defaultFile;
{
char inFileName[LINE_SIZE];
FILE *inFile = NULL;
StreamPtr inStream;
event_type newScore;
ulong notes, controls;
ulong junk;
#ifndef LIGHTSPEED
if ((defaultFile != NULL) && (strlen(defaultFile) > 0)) {
strcpy(inFileName, defaultFile);
} else {
gprintf(TRANS, "Score file?\n");
gets(inFileName);
if (strlen(inFileName) == 0) return NULL; /* never mind! */
}
#else
*inFileName = 0;
#endif
inFile = fileopen(inFileName, "gio", "r", "Adagio score file");
inStream = filestream_OpenRead(inFile);
if (inStream == NULL) {
/* should never happen */
gprintf(FATAL,
"Implementation: (adagio.c) Could not open input filestream.");
return NULL;
}
phase1_FreeMem(); /* free old score, if any */
newScore = phase1_Parse(inStream, ¬es, &controls); /* parse input */
stream_Close(inStream);
MaxMem(&junk);
gprintf(TRANS,
"Phase 1 completed; %ld note(s) and %ld ctrl(s) translated; %lu bytes free\n",
notes, controls, FreeMem());
return newScore;
}
/* play_mode -- play score until user quits */
/**/
void play_mode()
{
event_type score = new_score(NULL);
boolean done = false;
char response[100];
startTime = 0;
while (!done) {
gprintf(TRANS, "Type <Return> to play, ? for help, q to exit play mode:");
gets(response);
switch (*response) {
case 0:
play_pause_loop(score, startTime, NULL);
break;
case 'q':
case 'Q':
done = true;
break;
default:
default_response(*response);
}
}
}
/****************************************************************************
* play_pause_loop
* Inputs:
* event_type score: score to play
* ulong startTime: where to start playing
* StreamPtr outStream: stream to record to, if recording
* Effect:
* plays the music, simultaneously recording if outStream isn't NULL
****************************************************************************/
private void play_pause_loop(score, startTime, outStream)
event_type score;
ulong startTime;
StreamPtr outStream;
{
ulong stop_time;
event_type stop_place = score;
int stop_reason;
boolean proceed = false;
if (startTime == 0) gprintf(TRANS, "Type <space> to stop, p to pause");
for (;;) {
gprintf(TRANS, "...");
phase2_Play(
stop_place, proceed, (outStream != NULL), startTime,
&stop_time, &stop_place, &stop_reason);
report_stop(score, stop_time, stop_reason);
if (stop_reason == PAUSE) {
char input[100];
proceed = true;
gets(input);
} else {
break; /* get out of this loop */
}
}
}
/* record_mode -- handle record commands until user exits */
/**/
void record_mode()
{
boolean done = false;
char response[100];
event_type score = new_score(NULL);
while (!done) {
gprintf(TRANS, "Type <Return> to record, ? for help, q to exit record mode:");
gets(response);
switch (*response) {
case 0:
{
FILE *outFile;
StreamPtr outStream;
boolean do_pitch_bend = false;
outFile = fileopen("", "gio", "w", "File to record into");
outStream = filestream_OpenWrite(outFile);
if (outStream == NULL) {
gprintf(FATAL, "Could not open output file.");
return;
}
do_pitch_bend =
askbool("Enable recording of pitch bend information",
false);
rec_init(do_pitch_bend);
play_pause_loop(score, startTime, outStream);
rec_final(outStream, true);
}
break;
case 'q':
case 'Q':
done = true;
break;
default:
default_response(*response);
}
}
}
/****************************************************************************
* report_activity
* Effect:
* reports currently playing notes or recently played notes in each voice
****************************************************************************/
/* RECENTLY determines how far back to look for "recent" notes to report
* it is currently set to two seconds in hundreths of a second
*/
#define RECENTLY 200
/* structure used by report_activity: */
struct ActivityRecord {
boolean played;
boolean reported;
int line;
ulong start_time;
};
private void report_activity(score, stop_time)
event_type score;
ulong stop_time;
{
struct ActivityRecord voice[MAX_CHANNELS + 1];
/* voice[] keeps the state of each voice at stop_time
* (NOTE: voice[0] is unused) */
event_type n;
int i;
/* initialize voice record array */
for (i = 1; i <= MAX_CHANNELS; i++) {
voice[i].played = voice[i].reported = false;
}
gprintf(TRANS, "At time %ld (hundreths of a second):\n", stop_time);
for (n = score; n != NULL; n = n->next) {
if (is_note(n) &&
(n->ntime <= stop_time)) {
/* found a note which started before stop_time */
if ((n->ntime + n->u.note.ndur) >= stop_time) {
/* report if it was playing at stop_time */
gprintf(TRANS, " Voice %d was playing line %d\n",
n->nvoice, n->nline);
voice[n->nvoice].reported = true;
} else {
/* otherwise remember it; it might be the last note played */
voice[n->nvoice].played = true;
voice[n->nvoice].start_time = n->ntime;
voice[n->nvoice].line = n->nline;
}
}
} /* end of score traversal */
for (i = 1; i <= MAX_CHANNELS; i++) {
if ( voice[i].played &&
!voice[i].reported &&
(voice[i].start_time + RECENTLY >= stop_time))
gprintf(TRANS, " Voice %d recently played line %d\n",
i, voice[i].line);
}
}
/****************************************************************************
* report_modes
* Effect:
* report state of various operation modes
****************************************************************************/
private void report_modes()
{
gprintf(TRANS, "\n");
gprintf(TRANS, "MIDI byte trace (m option) %s\n",
(miditrace ? "on" : "off"));
gprintf(TRANS, "Music operation trace (t option) %s\n\n",
(musictrace ? "on" : "off"));
}
/****************************************************************************
* report_stop
* Inputs:
* event_type score: the score that was being played
* ulong stop_time: the time that playing was stopped
* int stop_reason: the reason that playing was stopped
* Effect:
* announce stopped state and (under some conditions) tell
* what was playing (or recently played) when we stopped
****************************************************************************/
private void report_stop(score, stop_time, stop_reason)
event_type score;
ulong stop_time;
int stop_reason;
{
gprintf(TRANS, "\n");
switch(stop_reason) {
case STOP_REQ:
gprintf(TRANS, " * * STOPPED * *\n");
gprintf(TRANS, "Stopped at user's request\n");
break;
case OUT_OF_MEMORY:
gprintf(TRANS, " * * STOPPED * *\n");
gprintf(TRANS, "Out of memory for recording\n");
break;
case PAUSE:
gprintf(TRANS, "Pause at %lu", stop_time);
return; /* quit early -- don't print activity */
break;
case END_SCORE:
gprintf(TRANS, "Done!\n");
return; /* quit early -- don't print activity */
break;
default:
/* never happens */
gprintf(FATAL,
"Implementation error (adagio.c): unknown stop reason.");
clean_exit();
break;
}
if (stop_time > 0) {
report_activity(score, stop_time);
}
}
/****************************************************************************
* main
* Inputs:
* int argc: count of arguments
* char * argv[]: vector of argument pointers
* Effect:
* runs adagio
****************************************************************************/
public void _main(argc, argv)
int argc;
char *argv[];
{
event_type score = NULL;
#ifdef MPW
setvbuf(stdout, NULL, _IOLBF, 0);
/* set i/o buffering to dump output buffer every line */
#endif
/* command line processing: */
cl_init(switches, nswitches, options, noptions, argv, argc);
if (cl_switch("-help") || cl_switch("-h")) {
cmdline_help();
return;
}
if (cl_switch("-simulated") || cl_switch("-s")) {
mpuexists(false);
}
MaxApplZone(); /* use all possible space */
timereset(); /* reset time */
off_init(); /* initialize note-off event manager */
if (cl_arg(1) != NULL) {
/* if file name argument given, try to read score from that file */
/* score = new_score(cl_arg(1)); */
gprintf("Ignoring '%s' in switch list\n", cl_arg(1));
}
cmd_loop(score); /* git down and BOOGEY! */
phase1_FreeMem();
}
void transcribe_mode()
{
boolean done = false;
char response[100];
while (!done) {
gprintf(TRANS,
"Type <Return> to transcribe, ? for help, q to exit transcribe mode:");
gets(response);
switch (*response) {
case 0:
{
FILE *outFile;
StreamPtr outStream;
boolean do_pitch_bend = false;
outFile = fileopen("", "gio", "w", "File to record into");
outStream = filestream_OpenWrite(outFile);
if (outStream == NULL) {
gprintf(FATAL, "Could not open output file.");
return;
}
do_pitch_bend =
askbool("Enable recording of pitch bend information",
false);
rec_init(do_pitch_bend);
play_pause_loop(NULL, 0, outStream);
rec_final(outStream, false);
}
break;
case 'q':
case 'Q':
done = true;
break;
default:
default_response(*response);
}
}
}